package com.mryan.metrics.utils;

import com.google.gson.Gson;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import javax.xml.crypto.Data;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * @description： 非侵入式接口信息计数 切面处
 * @Author MRyan
 * @Date 2021/1/24 12:07
 * @Version 1.0
 */
@Aspect
@Component
public class MetricsSettings {

    private Map<String, List<Double>> responseTimes = new ConcurrentHashMap<>();

    private Map<String, List<Double>> requestTimes = new ConcurrentHashMap<>();

    private ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();

    private boolean isShow = false;

    @Around(value = "@annotation(metrics)")
    public void interceptMetrics(ProceedingJoinPoint proceedingJoinPoint, Metrics metrics) throws Throwable {
        //根据注解参数 决定是否开启监听  以指定的频率统计数据并输出结果
        if (metrics.showAllMessageByTimeUnit()) {
            if (!isShow) {
                startRepeatedReport(60, TimeUnit.SECONDS);
            }
            isShow = true;
        }

        Signature signature = proceedingJoinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        String declaringTypeName = signature.getDeclaringTypeName();
        String methodName = method.getName();
        String allTypeMethodName = declaringTypeName + "." + methodName;
        //前置处理
        long startTimestamp = System.currentTimeMillis();
        //执行逻辑
        proceedingJoinPoint.proceed();
        //后置处理
        long respTime = System.currentTimeMillis() - startTimestamp;

        //记录接口响应时间
        recordResponseTime(allTypeMethodName, respTime);
        //记录接口请求时间
        recordRequestTimestamp(allTypeMethodName, startTimestamp);

        //根据注解参数决定是否 输出单次接口信息
        if (metrics.realtimeDisplay() == true) {
            System.out.println(getAllTypeMsg());
        }
    }


    /**
     * 以指定的频率统计数据并输出结果
     *
     * @param period
     * @param unit
     */
    public void startRepeatedReport(long period, TimeUnit unit) {
        executor.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                System.out.println(getAllTypeMsg());
            }
        }, 0, period, unit);
    }

    /**
     * 获取接口调用信息 调用接口集合的最大值，调用接口集合的平均值，调用次数
     *
     * @return
     */
    public String getAllTypeMsg() {
        Gson gson = new Gson();
        Map<String, Map<String, Object>> stats = new HashMap<>();
        //遍历相应时间
        for (Map.Entry<String, List<Double>> entry : responseTimes.entrySet()) {
            String apiName = entry.getKey();
            List apiRespTimes = entry.getValue();
            stats.putIfAbsent(apiName, new HashMap<>());
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date date = new Date();
            stats.get(apiName).put("time", simpleDateFormat.format(date));
            stats.get(apiName).put("max", max(apiRespTimes));
            stats.get(apiName).put("avg", avg(apiRespTimes));
        }

        for (Map.Entry<String, List<Double>> entry : requestTimes.entrySet()) {
            String apiName = entry.getKey();
            List apiTimestamps = entry.getValue();
            stats.putIfAbsent(apiName, new HashMap<>());
            stats.get(apiName).put("count", (double) apiTimestamps.size());
        }
        return gson.toJson(stats);
    }


    private double max(List<Double> dataset) {
        if (dataset == null || dataset.size() == 0) {
            throw new RuntimeException("List is empty.");
        }
        Double max = Double.MIN_VALUE;
        for (Double timestamp : dataset) {
            max = Math.max(max, timestamp);
        }
        return max;
    }

    private double avg(List<Double> dataset) {
        if (dataset == null || dataset.size() == 0) {
            throw new RuntimeException("List is empty.");
        }
        Double sum = 0D;
        for (Double responseTime : dataset) {
            sum += responseTime;
        }
        return sum / dataset.size();
    }

    /**
     * 记录接口请求的响应时间
     *
     * @param apiName
     * @param responseTime
     */
    public void recordResponseTime(String apiName, double responseTime) {
        responseTimes.putIfAbsent(apiName, new ArrayList<>());
        responseTimes.get(apiName).add(responseTime);
    }

    /**
     * @description:
     * @param: [apiName, requestTimestamp]
     * @return: void
     * @author: ZhangDaChen
     * @date: 2021-09-08
     */
    public void recordRequestTimestamp(String apiName, double requestTimestamp) {
        requestTimes.putIfAbsent(apiName, new ArrayList<>());
        requestTimes.get(apiName).add(requestTimestamp);
    }

}
